package control;

import java.util.ArrayList;
import java.util.List;

import foundation.SurModel.rndForest.RndForestSurModel;
import foundation.SurModel.rndForest.sample.MLearnTbl;
import foundation.SurModel.rndForest.sample.PerfLearnTblItem;
import foundation.fileUtil.TxtFileUtil;
import foundation.pcmUtil.RptFileHelper;
import foundation.pcmUtil.SimulatorMouse;

public class PerfEvaluator {
	protected ExeCtx exeCtx = null;
	protected String basePath = null;
	protected List<StringBuffer> curDfCodes = null;
	protected int curPerfSolveNum = 0;// 当前求解性能指标的次数
	protected int curPredPerfNum = 0;// 当前预测性能指标的次数
	protected boolean isInPredPhase = false;// 起始时处于解析阶段，而非预测阶段
	// protected boolean useMLearn = false;// 否使用机器学习
	protected int sampleNum = 400;// 采样的样本数， 在求解真值状态下，采得样本数超过该值就触发机器学习;
	protected int predictNum = 14 * 30 * 20;// 预测次数，超过该次数需要求解真值
	protected MLearnTbl mlTbl = MLearnTbl.getInstance();
	// 代理模型类
	RndForestSurModel model = RndForestSurModel.getInstance();
	// 性能报告阅读助手类
	RptFileHelper rptFileHelper = null;

	public PerfEvaluator(ExeCtx exeCtx) {
		this.exeCtx = exeCtx;
		basePath = exeCtx.getRunBasePath();
		curDfCodes = exeCtx.getCurFdCodes();
		// useMLearn = exeCtx.isUseMLearn();
		sampleNum = exeCtx.getSampleNum();
		predictNum = exeCtx.getPredictNum();
	}

	/**
	 * 解析性能并生成评估报告
	 */
	public synchronized void solvePerformance() {// 由控制器保障当前SA更新
		// 删除上次解析的结果
//		TxtFileUtil.deleteFile(basePath, "lqxo");
		// 性能解析
//		exeCtx.getSaSolver().RunPCMSolver();
		SimulatorMouse.runS4c();
	}

	/**
	 * 获取部署有组件的server列表
	 * 
	 * @param mlDfcodes:用于机器学习的自由度实例编码
	 * @return
	 */
	public List<Integer> getUsedProcNum(List<StringBuffer> mlDfcodes) {
		List<Integer> serverNums = new ArrayList<Integer>();
		ArrayList<Integer> strtIdxs = exeCtx.getStrtIdxs();
		for (int i = strtIdxs.get(1); i < strtIdxs.get(2); i++) {
			int srvNum = Integer.valueOf(mlDfcodes.get(i).toString());
			serverNums.add(srvNum);
		}
		List<Integer> alloSrvNums = new ArrayList<Integer>();
		alloSrvNums.add(serverNums.get(0));
		for (int i = 1; i < serverNums.size(); i++) {
			for (int j = 0; j < alloSrvNums.size(); j++) {
				if (serverNums.get(i) == alloSrvNums.get(j)) {
					break;
				} else if (j == alloSrvNums.size() - 1) {
					alloSrvNums.add(serverNums.get(i));
				}
			}
		}
		return alloSrvNums;
	}

	public boolean isValidServer(List<StringBuffer> mlDfCodes, int procNo) {
		boolean rlt = false;
		List<Integer> serverNums =getUsedProcNum(mlDfCodes);
		for (int serverNo : serverNums) {
			if (serverNo == procNo) {
				rlt = true;
				break;
			}
		}
		return rlt;
	}

	public PerfLearnTblItem getPerfIndicesBySolve() {
		PerfLearnTblItem perfTblItem = new PerfLearnTblItem();
		solvePerformance();// 解析
		rptFileHelper = exeCtx.getPerfRptHlper();// 设置报告的帮助类
		// 读取响应时间
		float resTime = rptFileHelper.getRest(exeCtx.getUsageScenarioProer());
		perfTblItem.setActualresTime(resTime);
		// 获取最大使用率处理器编号
//		String maxUtilSvrNm = rptFileHelper.getMaxUtilSvr();
//
//		int maxUtilProcNo = exeCtx.getServerNo(maxUtilSvrNm);
//		perfTblItem.setActualmaxUtilProcNo(maxUtilProcNo);
//
//		// 获取最小使用率处理器编号
//		String minUtilSvrNm = rptFileHelper.getMinUtilSvr();
//		int minUtilProcNo = exeCtx.getServerNo(minUtilSvrNm);
//		perfTblItem.setActualminUtilProcNo(minUtilProcNo);

		// 设定自由度
		List<StringBuffer> mlDfCodes = exeCtx.toMLDfcodes();
		perfTblItem.setMlDFcodes(mlDfCodes);
		return perfTblItem;
	}

	/**
	 * 在预测阶段获取响应时间、最高使用率处理器和最低使用率处理器
	 * 
	 * @return
	 */
	public PerfLearnTblItem getIndiceInpredictPahase() {
		PerfLearnTblItem perfTblItem = new PerfLearnTblItem();
		curPredPerfNum++;
		if (curPredPerfNum <= predictNum) {// 通过预测获取性能指标并加入性能学习表
			List<StringBuffer> mlDfCodes = exeCtx.toMLDfcodes();
			perfTblItem.setMlDFcodes(mlDfCodes);// 设定自由度
			float resTime = Float.MAX_VALUE;
			try {
				resTime = model.predictRest(mlDfCodes);// 预测响应时间
				boolean isValidResTime=Float.compare(resTime, 0f)>0;
				if (!isValidResTime) {// 判断预测结果的合法性，不合法则求解真实值
					// 求解真实值
					perfTblItem = getPerfIndicesBySolve();
					//curPerfSolveNum++;
					// 将预测值设置为真实值
					float actualresTime = perfTblItem.getActualresTime();
					perfTblItem.setPredictResTime(actualresTime);

				} else {
					perfTblItem.setPredictResTime(resTime);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}

		} else {// 预测阶段结束，转入解析阶段
			isInPredPhase = false;
			curPredPerfNum = 0;
			// curPerfSolveNum = 0;
			perfTblItem = getIndiceInSolvePhase();// 进入解析阶段
		}
		return perfTblItem;
	}

	/**
	 * 在解析阶段获取响应时间
	 * 
	 * @return
	 */
	protected PerfLearnTblItem getIndiceInSolvePhase() {
		PerfLearnTblItem perfTblItem = new PerfLearnTblItem();
		curPerfSolveNum++;
		if (curPerfSolveNum <= sampleNum) {// 通过解析获取真实响应时间
			// 在当前上下文中解析性能指标
			perfTblItem = getPerfIndicesBySolve();
		} else {// 解析阶段结束，转预测阶段
			isInPredPhase = true;
			// curPredPerfNum = 0;
			curPerfSolveNum = 0;
			model.trainRest();// 启动模型训练，为预测作准备,以下代码后续迭代需要改进；
			perfTblItem = getIndiceInpredictPahase();// 进入预测阶段
		}
		return perfTblItem;
	}

	public PerfIndice getFrm(PerfLearnTblItem perfTblItem) {
		PerfIndice perfIndice = new PerfIndice();
		if (Float.compare(perfTblItem.getActualresTime(), -1) == 0) {
			perfIndice.setResTime(perfTblItem.getPredictResTime());
		} else {
			perfIndice.setResTime(perfTblItem.getActualresTime());
		}
		return perfIndice;
	}

	/**
	 * 获取当前上下文中的性能指标
	 */
	public PerfIndice getPerfIndice() {
		
		PerfIndice perfIndice = null;
		exeCtx.setUseMLearn(false);
		if (exeCtx.isUseMLearn()) {// 使用机器学习
			if (isInPredPhase) {// 预测阶段
				PerfLearnTblItem perfTblItem = getIndiceInpredictPahase();
				mlTbl.addPerfItem(perfTblItem);
				perfIndice = getFrm(perfTblItem);
			} else {// 解析阶段
				PerfLearnTblItem perfTblItem = getIndiceInSolvePhase();
				mlTbl.addPerfItem(perfTblItem);
				perfIndice = getFrm(perfTblItem);
			}
		} else {// 不使用机器学习，直接解析
			perfIndice = new PerfIndice();
			solvePerformance();// 解析
			RptFileHelper rptFileHelper = getRptFileHelper();// 获取报告的帮助类
			// 读取响应时间
			rptFileHelper = exeCtx.getPerfRptHlper();// 设置报告的帮助类
			// 读取响应时间
			Float resTime = rptFileHelper.getRest(exeCtx.getUsageScenarioProer());
			perfIndice.setResTime(resTime);
			// 获取最大使用率处理器
			String maxUtilSvrNm = rptFileHelper.getMaxUtilSvr();
			perfIndice.setMaxUtilSvrNm(maxUtilSvrNm);
			// 获取最小使用率处理器
			String minUtilSvrNm = rptFileHelper.getMinUtilSvr();
			perfIndice.setMinUtilSvrNm(minUtilSvrNm);

		}
		return perfIndice;
	}

	public int getCurPerfSolveNum() {
		return curPerfSolveNum;
	}

	public void setCurPerfSolveNum(int curPerfSolveNum) {
		this.curPerfSolveNum = curPerfSolveNum;
	}

	public int getCurPredPerfNum() {
		return curPredPerfNum;
	}

	public void setCurPredPerfNum(int curPredPerfNum) {
		this.curPredPerfNum = curPredPerfNum;
	}

	public int getSampleNum() {
		return sampleNum;
	}

	public void setSampleNum(int sampleNum) {
		this.sampleNum = sampleNum;
	}

	public int getPredictNum() {
		return predictNum;
	}

	public void setPredictNum(int predictNum) {
		this.predictNum = predictNum;
	}

	public List<StringBuffer> getCurDfCodes() {
		return curDfCodes;
	}

	public void setCurDfCodes(List<StringBuffer> curDfCodes) {
		this.curDfCodes = curDfCodes;
	}

	public RndForestSurModel getModel() {
		return model;
	}

	public void setModel(RndForestSurModel model) {
		this.model = model;
	}

	public boolean isInPredPhase() {
		return isInPredPhase;
	}

	public void setInPredPhase(boolean isInPredPhase) {
		this.isInPredPhase = isInPredPhase;
	}

	// public boolean isUseMLearn() {
	// return useMLearn;
	// }
	//
	// public void setUseMLearn(boolean useMLearn) {
	// this.useMLearn = useMLearn;
	// }

	public RptFileHelper getRptFileHelper() {
		return rptFileHelper;
	}

	public void setRptFileHelper(RptFileHelper rptFileHelper) {
		this.rptFileHelper = rptFileHelper;
	}

	public MLearnTbl getMlTbl() {
		return mlTbl;
	}

	public void setMlTbl(MLearnTbl mlTbl) {
		this.mlTbl = mlTbl;
	}

}
